home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs20.zoo / outfloat.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-13  |  5.6 KB  |  184 lines

  1. //    This is part of the iostream library, providing input/output for C++.
  2. //    Copyright (C) 1992 Per Bothner.
  3. //
  4. //    This library is free software; you can redistribute it and/or
  5. //    modify it under the terms of the GNU Library General Public
  6. //    License as published by the Free Software Foundation; either
  7. //    version 2 of the License, or (at your option) any later version.
  8. //
  9. //    This library is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. //    Library General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU Library General Public
  15. //    License along with this library; if not, write to the Free
  16. //    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #include <ioprivat.h>
  19.  
  20. // Format floating-point number and print them.
  21. // Return number of chars printed, or EOF on error.
  22.  
  23. // sign_mode == '+' : print "-" or "+"
  24. // sign_mode == ' ' : print "-" or " "
  25. // sign_mode == '\0' : print "-' or ""
  26.  
  27. int __outfloat(double value, streambuf *sb, char type,
  28.            int width, int precision, ios::fmtflags flags,
  29.            char sign_mode, char fill)
  30. {
  31.     int count = 0;
  32. #define PUT(x) do {if (sb->sputc(x) < 0) goto error; count++;} while (0)
  33. #define PUTN(p, n) \
  34.   do {_G_size_t _n=n; count+=_n; if (sb->sputn(p,_n) != _n) goto error;} while(0)
  35. #define PADN(fill, n) \
  36.   do {_G_size_t _n = n; count+=_n; if (sb->padn(fill, _n) < 0) goto error;} while (0)
  37.     ios::fmtflags pad_kind = flags & (ios::left|ios::right|ios::internal);
  38.     int skip_zeroes = 0;
  39.     int show_dot = (flags & ios::showpoint) != 0;
  40.     int decpt;
  41.     int sign;
  42.     int mode;
  43. #define EBUF_SIZE 12
  44. #define EBUF_END &ebuf[EBUF_SIZE]
  45.     char ebuf[EBUF_SIZE];
  46.     char *end;
  47.     int exp = 0;
  48.     switch (type) {
  49.       case 'f':
  50.     mode = 3;
  51.     break;
  52.       case 'e':
  53.       case 'E':
  54.     exp = type;
  55.     mode = 2;
  56.     if (precision != 999)
  57.       precision++;  // Add one to include digit before decimal point.
  58.     break;
  59.       case 'g':
  60.       case 'G':
  61.     exp = type == 'g' ? 'e' : 'E';
  62.     if (precision == 0) precision = 1;
  63.     if (!(flags & ios::showpoint))
  64.         skip_zeroes = 1;
  65.     type = 'g';
  66.     mode = 2;
  67.     break;
  68.     }
  69.     /* Do the actual convension */
  70.     if (precision == 999 && mode != 3)
  71.       mode = 0;
  72.     char *p = dtoa(value, mode, precision, &decpt, &sign, &end);
  73.     register int i;
  74.     int useful_digits = end-p;
  75.     char *exponent_start = EBUF_END;
  76.     if (mode == 0)
  77.       precision = useful_digits;
  78.     // Check if we need to emit an exponent.
  79.     if (mode != 3 && decpt != 9999) {
  80.     i = decpt - 1;
  81.     if ((type != 'g' && type != 'F') || i < -4 || i >= precision) {
  82.         // Print the exponent into ebuf.
  83.         // We write ebuf in reverse order (right-to-left).
  84.         char sign;
  85.         if (i >= 0)
  86.         sign = '+';
  87.         else
  88.         sign = '-', i = -i;
  89.         /* Note: ANSI requires at least 2 exponent digits. */
  90.         do {
  91.         *--exponent_start = (i % 10) + '0';
  92.         i /= 10;
  93.         } while (i >= 10);
  94.         *--exponent_start = i + '0';
  95.         *--exponent_start = sign;
  96.         *--exponent_start = exp;
  97.     }
  98.     }
  99.     int exponent_size = EBUF_END - exponent_start;
  100.     if (mode == 1)
  101.     precision = 1;
  102.     /* If we print an exponent, always show just one digit before point. */
  103.     if (exponent_size)
  104.     decpt = 1;
  105.     if (decpt == 9999) { // Infinity or NaN
  106.     decpt = useful_digits;
  107.     precision = 0;
  108.     show_dot = 0;
  109.     }
  110.  
  111.    // dtoa truncates trailing zeroes.  Set the variable trailing_zeroes to
  112.    // the number of 0's we have to add (after the decimal point).
  113.    int trailing_zeroes = 0;
  114.    if (skip_zeroes)
  115.        trailing_zeroes = 0;
  116.    else if (type == 'f')
  117.        trailing_zeroes = useful_digits <= decpt ? precision
  118.        : precision-(useful_digits-decpt);
  119.    else if (exponent_size) // 'e' 'E' or 'g' format using exponential notation.
  120.        trailing_zeroes = precision - useful_digits;
  121.    else // 'g' format not using exponential notation.
  122.        trailing_zeroes = useful_digits <= decpt ? precision - decpt
  123.        : precision-useful_digits;
  124.     if (trailing_zeroes < 0) trailing_zeroes = 0;
  125.  
  126.     if (trailing_zeroes != 0 || useful_digits > decpt)
  127.     show_dot = 1;
  128.     int print_sign;
  129.     if (sign_mode == 0)
  130.     print_sign = sign ? '-' : 0;
  131.     else if (sign_mode == '+')
  132.     print_sign = sign ? '-' : '+';
  133.     else /* if (sign_mode == ' ') */
  134.     print_sign = sign ? '-' : ' ';
  135.     
  136.     // Calculate the width (before padding).
  137.     int unpadded_width =
  138.     (print_sign != 0) + trailing_zeroes + exponent_size + show_dot
  139.         + useful_digits
  140.         + (decpt > useful_digits ? decpt - useful_digits
  141.            : decpt > 0 ? 0 : 1 - decpt);
  142.  
  143.     int padding = width > unpadded_width ? width - unpadded_width : 0;
  144.     if (padding > 0
  145.     && pad_kind != (ios::fmtflags)ios::left
  146.     && pad_kind != (ios::fmtflags)ios::internal) // Default (right) adjust.
  147.     PADN(fill, padding);
  148.     if (print_sign)
  149.     PUT(print_sign);
  150.     if (pad_kind == (ios::fmtflags)ios::internal && padding > 0)
  151.     PADN(fill, padding);
  152.     if (decpt > 0) {
  153.     if (useful_digits >= decpt)
  154.         PUTN(p, decpt);
  155.     else {
  156.         PUTN(p, useful_digits);
  157.         PADN('0', decpt-useful_digits);
  158.     }
  159.     if (show_dot) {
  160.         PUT('.');
  161.         // Print digits after the decimal point.
  162.         if (useful_digits > decpt)
  163.         PUTN(p + decpt, useful_digits-decpt);
  164.     }
  165.     }
  166.     else {
  167.     PUT('0');
  168.     if (show_dot) {
  169.         PUT('.');
  170.         PADN('0', -decpt);
  171.         // Print digits after the decimal point.
  172.         PUTN(p, useful_digits);
  173.     }
  174.     }
  175.     PADN('0', trailing_zeroes);
  176.     if (exponent_size)
  177.     PUTN(exponent_start, exponent_size);
  178.     if (pad_kind == (ios::fmtflags)ios::left && padding > 0) // Left adjustment
  179.     PADN(fill, padding);
  180.     return count;
  181.   error:
  182.     return EOF;
  183. }
  184.